package com.zanglikun.refrence;

import java.util.ArrayList;

/**
 * Java 引用与对象身份演示
 *
 * 演示目的：
 * 证明集合存储的是引用的副本，修改引用变量不会影响集合中的元素
 *
 * 关键概念：
 * 1. 引用传递 - 集合存储的是引用的副本，而非对象本身
 * 2. 身份哈希码 - System.identityHashCode() 用于获取对象的内存地址标识
 * 3. Integer缓存 - [-128, 127] 范围内的Integer会被缓存，超出范围每次都创建新对象
 *
 * @author : zanglikun
 * @date : 2025/6/18 21:25
 * @desc : Copyright © zanglikun.com
 */
public class TestForRefrence {

    private static final String SEPARATOR = buildSeparator(60);
    private static final String TITLE = "  Java 引用与对象身份演示 - System.identityHashCode()";

    public static void main(String[] args) {
        printSeparator();
        System.out.println(TITLE);
        printSeparator();

        // 【第一步】创建Integer对象
        Integer a = 1000;
        int initialHash = System.identityHashCode(a);
        System.out.println("\n【步骤1】初始化 Integer a = 1000");
        System.out.println("  a 的身份哈希码: " + initialHash);
        System.out.println("  a 指向的对象: " + a);
        System.out.println("  说明: 1000超出Integer缓存范围[-128,127]，每次创建新对象\n");

        // 【第二步】将a添加到集合
        ArrayList<Integer> lists = new ArrayList<>();
        lists.add(a);
        int listElementHash = System.identityHashCode(lists.get(0));
        System.out.println("【步骤2】将 a 添加到 ArrayList");
        System.out.println("  集合内容: " + lists);
        System.out.println("  集合中元素的身份哈希码: " + listElementHash);
        System.out.println("  初始状态: 集合中元素和 a 指向同一对象\n");

        // 【第三步】循环中修改a的引用
        System.out.println("【步骤3】修改局部变量 a 的引用");
        System.out.println("  执行: a = Integer.valueOf(\"1000\")\n");

        // 只需一次迭代，集合中就一个元素
        Integer ele = lists.get(0);
        int eleHash = System.identityHashCode(ele);
        System.out.println("  修改前:");
        System.out.println("    • 集合元素的身份哈希码: " + eleHash);
        System.out.println("    • 集合中的值: " + ele);
        System.out.println("    • a 的身份哈希码: " + System.identityHashCode(a));

        // 修改局部变量a的引用
        a = Integer.valueOf("1000");
        int newHash = System.identityHashCode(a);

        System.out.println("\n  修改后:");
        System.out.println("    • a 的身份哈希码: " + newHash);
        System.out.println("    • a 的值: " + a);
        System.out.println("    • 集合元素的身份哈希码: " + eleHash);
        System.out.println("    • 集合中的值: " + ele);
        System.out.println("\n  对比结果:");
        System.out.println("    • a 是否指向新对象? " + (eleHash != newHash ? "✓ 是 (不同对象)" : "✗ 否"));
        System.out.println("    • 集合中的元素是否改变? " + (ele.equals(lists.get(0)) ? "✓ 否 (保持不变)" : "✗ 是"));

        // 【第四步】验证结果
        System.out.println("\n【步骤4】最终验证");
        System.out.println("  a 的身份哈希码: " + System.identityHashCode(a));
        System.out.println("  a 的值: " + a);
        System.out.println("  集合中元素的身份哈希码: " + System.identityHashCode(lists.get(0)));
        System.out.println("  集合内容: " + lists);

        // 【结论】
        printSeparator();
        System.out.println("  【核心结论】");
        System.out.println("  ✓ 集合存储的是引用的副本，而非对象本身");
        System.out.println("  ✓ 修改局部变量 a 的引用指向，不会影响集合中的元素");
        System.out.println("  ✓ 这演示了 Java 中 '按值传递引用' 的特性");
        System.out.println("  ✓ 集合中的元素始终指向原始对象");
        printSeparator();
    }

    /**
     * 打印分隔线
     */
    private static void printSeparator() {
        System.out.println(SEPARATOR);
    }

    /**
     * 构造分隔线（JDK 8 兼容）
     *
     * @param length 分隔线长度
     * @return 由 '═' 组成的分隔线
     */
    private static String buildSeparator(int length) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++) {
            sb.append("═");
        }
        return sb.toString();
    }
}
